package de.ret_world.openrpgstudio.mediamanager;

import buoy.event.CommandEvent;
import buoy.event.SelectionChangedEvent;
import buoy.event.WindowClosingEvent;
import buoy.widget.*;
import de.ret_world.openrpgstudio.editor.Media;
import de.ret_world.openrpgstudio.editor.Project;
import de.ret_world.openrpgstudio.editor.gui.AudioPreviewWidget;
import de.ret_world.openrpgstudio.editor.gui.ImagePreviewWidget;
import de.ret_world.openrpgstudio.editor.helpers.Internationalization;
import de.ret_world.openrpgstudio.editor.plugininterfaces.ToolPlugin;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileFilter;
import org.java.plugin.PluginLifecycleException;
import org.java.plugin.registry.Extension;
import org.java.plugin.registry.ExtensionPoint;

/**
 * MediaTool GUI.
 *
 * @author emu
 */
public class MediaTool extends ToolPlugin {

    /**
     * This plug-in ID.
     */
    public static final String PLUGIN_ID = "de.ret_world.openrpgstudio.mediamanager";
    //Variables
    private BFrame parent;
    private BDialog dialog;
    private BSplitPane splitI;
    private BSplitPane splitS;
    private BSplitPane splitM;
    private BTextField txtPathI;
    private BTextField txtUsersI;
    private ImagePreviewWidget ipw;
    private BTextField txtPathS;
    private BTextField txtUsersS;
    private AudioPreviewWidget apwS;
    private BTextField txtPathM;
    private BTextField txtUsersM;
    private AudioPreviewWidget apwM;
    private BList lstImages;
    private BList lstSounds;
    private BList lstMusic;
    private BTabbedPane tabbed;
    private ArrayList<MediaTabPlugin> plugins;

    @Override
    public void init(BMenuItem menu, BButton button, BFrame parent) {
        this.parent = parent;

        menu.addEventLink(CommandEvent.class, this, "showGUI");
        button.addEventLink(CommandEvent.class, this, "showGUI");

        plugins = new ArrayList<>();
    }

    @Override
    public Shortcut getShortcut() {
        return new Shortcut(KeyEvent.VK_M, Shortcut.CTRL_MASK);
    }

    private void showGUI() {
        Internationalization intn = Internationalization.getInstance();

        dialog = new BDialog(parent, intn.getString("MM.MEDIAMANAGER"), true);
        dialog.addEventLink(WindowClosingEvent.class, this, "close");

        LayoutInfo li = new LayoutInfo(LayoutInfo.WEST, LayoutInfo.HORIZONTAL, new Insets(5, 5, 5, 5), null);

        BorderContainer bc = new BorderContainer();
        tabbed = new BTabbedPane();

        splitI = new BSplitPane(BSplitPane.HORIZONTAL);
        splitI.setDividerLocation(Integer.parseInt(config.getProperty("dialog.divider.i", "175")));

        //Left
        lstImages = new BList();
        lstImages.addEventLink(SelectionChangedEvent.class, this, "selectionChanged");
        BScrollPane scrl = new BScrollPane(lstImages, BScrollPane.SCROLLBAR_NEVER, BScrollPane.SCROLLBAR_AS_NEEDED);
        scrl.setForceHeight(true);
        scrl.setForceWidth(true);
        splitI.add(scrl, 0);

        //Right
        BorderContainer bcr = new BorderContainer();

        ipw = new ImagePreviewWidget(false);
        bcr.add(ipw, BorderContainer.CENTER, new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH, new Insets(5, 5, 5, 5), null));
        BorderContainer bcri = new BorderContainer();
        bcri.add(new BLabel(intn.getString("MM.PATH") + " :"), BorderContainer.WEST, li);
        txtPathI = new BTextField(15);
        txtPathI.setEditable(false);
        bcri.add(txtPathI, BorderContainer.CENTER, li);
        BorderContainer bcrii = new BorderContainer();
        bcrii.add(new BLabel(intn.getString("MM.USERS") + ": "), BorderContainer.NORTH, li);
        txtUsersI = new BTextField();
        txtUsersI.setEditable(false);
        bcrii.add(txtUsersI, BorderContainer.CENTER, new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH, new Insets(5, 5, 5, 5), null));
        bcri.add(bcrii, BorderContainer.SOUTH, new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH));
        bcr.add(bcri, BorderContainer.SOUTH, new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH, new Insets(5, 5, 5, 5), null));

        splitI.add(bcr, 1);

        tabbed.add(splitI, intn.getString("MM.IMAGES"));

        splitS = new BSplitPane(BSplitPane.HORIZONTAL);
        splitS.setDividerLocation(Integer.parseInt(config.getProperty("dialog.divider.s", "175")));

        //Left
        lstSounds = new BList();
        lstSounds.addEventLink(SelectionChangedEvent.class, this, "selectionChanged");
        scrl = new BScrollPane(lstSounds, BScrollPane.SCROLLBAR_NEVER, BScrollPane.SCROLLBAR_AS_NEEDED);
        scrl.setForceHeight(true);
        scrl.setForceWidth(true);
        splitS.add(scrl, 0);

        //Right
        bcr = new BorderContainer();

        apwS = new AudioPreviewWidget(false);
        bcr.add(apwS, BorderContainer.CENTER, new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH, new Insets(5, 5, 5, 5), null));
        bcri = new BorderContainer();
        bcri.add(new BLabel(intn.getString("MM.PATH") + " :"), BorderContainer.WEST, li);
        txtPathS = new BTextField(15);
        txtPathS.setEditable(false);
        bcri.add(txtPathS, BorderContainer.CENTER, li);
        bcrii = new BorderContainer();
        bcrii.add(new BLabel(intn.getString("MM.USERS") + ": "), BorderContainer.NORTH, li);
        txtUsersS = new BTextField();
        txtUsersS.setEditable(false);
        bcrii.add(txtUsersS, BorderContainer.CENTER, new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH, new Insets(5, 5, 5, 5), null));
        bcri.add(bcrii, BorderContainer.SOUTH, new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH));
        bcr.add(bcri, BorderContainer.SOUTH, new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH, new Insets(5, 5, 5, 5), null));

        splitS.add(bcr, 1);

        tabbed.add(splitS, intn.getString("MM.SOUNDS"));

        splitM = new BSplitPane(BSplitPane.HORIZONTAL);
        splitM.setDividerLocation(Integer.parseInt(config.getProperty("dialog.divider.m", "175")));

        //Left
        lstMusic = new BList();
        lstMusic.addEventLink(SelectionChangedEvent.class, this, "selectionChanged");
        scrl = new BScrollPane(lstMusic, BScrollPane.SCROLLBAR_NEVER, BScrollPane.SCROLLBAR_AS_NEEDED);
        scrl.setForceHeight(true);
        scrl.setForceWidth(true);
        splitM.add(scrl, 0);

        //Right
        bcr = new BorderContainer();

        apwM = new AudioPreviewWidget(true);
        bcr.add(apwM, BorderContainer.CENTER, new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH, new Insets(5, 5, 5, 5), null));
        bcri = new BorderContainer();
        bcri.add(new BLabel(intn.getString("MM.PATH") + " :"), BorderContainer.WEST, li);
        txtPathM = new BTextField(15);
        txtPathM.setEditable(false);
        bcri.add(txtPathM, BorderContainer.CENTER, li);
        bcrii = new BorderContainer();
        bcrii.add(new BLabel(intn.getString("MM.USERS") + ": "), BorderContainer.NORTH, li);
        txtUsersM = new BTextField();
        txtUsersM.setEditable(false);
        bcrii.add(txtUsersM, BorderContainer.CENTER, new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH, new Insets(5, 5, 5, 5), null));
        bcri.add(bcrii, BorderContainer.SOUTH, new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH));
        bcr.add(bcri, BorderContainer.SOUTH, new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH, new Insets(5, 5, 5, 5), null));

        splitM.add(bcr, 1);

        tabbed.add(splitM, intn.getString("MM.MUSIC"));

        //Plugin Extension Point "MediaTab"
        MediaTabPlugin plugin;
        BSplitPane pluginContainer = null;
        ExtensionPoint toolExtPoint = manager.getRegistry().getExtensionPoint(PLUGIN_ID, "MediaTab");
        for (Extension ext : toolExtPoint.getConnectedExtensions()) {
            //initialize the plugin
            if (manager.isPluginEnabled(ext.getDeclaringPluginDescriptor())) {
                try {
                    // Activate plug-in that declares extension.
                    manager.activatePlugin(ext.getDeclaringPluginDescriptor().getId());
                    //main.reloadInternationalization();
                    // Get plug-in class loader.
                    ClassLoader classLoader = manager.getPluginClassLoader(ext.getDeclaringPluginDescriptor());
                    // Load Tool class.
                    Class<?> clazz = classLoader.loadClass(ext.getParameter("class").valueAsString());
                    // Create Tool instance.
                    plugin = (MediaTabPlugin) clazz.newInstance();
                    plugins.add(plugin);
                    pluginContainer = new BSplitPane(BSplitPane.HORIZONTAL);
                    // Initialize class instance according to interface contract.
                    plugin.init(pluginContainer);

                    tabbed.add(pluginContainer, ext.getParameter("name").valueAsString());
                } catch (InstantiationException | IllegalAccessException | ClassNotFoundException | PluginLifecycleException ex) {
                    log.error(ex);
                }
            }
        }


        bc.add(BOutline.createEtchedBorder(tabbed, false), BorderContainer.CENTER, new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH, new Insets(5, 5, 5, 5), null));

        initLists();

        //Down
        RowContainer rc = new RowContainer();
        BButton btn = new BButton(intn.getString("CLOSE"));
        btn.addEventLink(CommandEvent.class, this, "close");
        rc.add(btn, li);
        btn = new BButton(intn.getString("MM.IMPORT"));
        btn.addEventLink(CommandEvent.class, this, "importMedia");
        rc.add(btn, li);
        btn = new BButton(intn.getString("MM.EXPORT"));
        btn.addEventLink(CommandEvent.class, this, "exportMedia");
        rc.add(btn, li);

        bc.add(rc, BorderContainer.SOUTH, li);

        dialog.setContent(bc);

        int x = Integer.parseInt(config.getProperty("dialog.loc.x", "150"));
        int y = Integer.parseInt(config.getProperty("dialog.loc.y", "150"));
        int w = Integer.parseInt(config.getProperty("dialog.size.w", "700"));
        int h = Integer.parseInt(config.getProperty("dialog.size.h", "500"));

        dialog.setBounds(new Rectangle(x, y, w, h));
        dialog.setVisible(true);
    }

    private void initLists() {
        lstImages.removeAll();
        lstSounds.removeAll();
        lstMusic.removeAll();
        for (Media m : Project.getInstance().getMediaManager().getMediaMap().values()) {
            switch (m.getType()) {
                case Media.IMAGE:
                    lstImages.add(m);
                    break;
                case Media.SOUND:
                    lstSounds.add(m);
                    break;
                case Media.MUSIC:
                    lstMusic.add(m);
                    break;
                default:
                    for (MediaTabPlugin plugin : plugins) {
                        if (m.getType() == plugin.getMediaTypeNr()) {
                            plugin.addMedia(m);
                        }
                    }
                    break;
            }
        }
    }

    private void close() {
        log.info("Saving configuration files");

        config.setProperty("dialog.loc.x", "" + dialog.getBounds().x);
        config.setProperty("dialog.loc.y", "" + dialog.getBounds().y);
        config.setProperty("dialog.size.w", "" + dialog.getBounds().width);
        config.setProperty("dialog.size.h", "" + dialog.getBounds().height);
        config.setProperty("dialog.divider.i", "" + splitI.getDividerLocation());
        config.setProperty("dialog.divider.s", "" + splitS.getDividerLocation());
        config.setProperty("dialog.divider.m", "" + splitM.getDividerLocation());

        for (MediaTabPlugin mtp : plugins) {
            mtp.save();
        }

        dialog.dispose();
    }

    private void selectionChanged(SelectionChangedEvent ev) {
        Internationalization intn = Internationalization.getInstance();
        Project project = Project.getInstance();
        if (ev.getWidget().equals(lstImages)) {
            if (lstImages.getSelectedIndex() > -1) {
                Media m = (Media) lstImages.getSelectedValue();
                txtPathI.setText(m.getFile().toString());
                if (!m.getUsers().isEmpty()) {
                    String s = "";
                    for (String str : m.getUsers()) {
                        s += str + ", ";
                    }
                    txtUsersI.setText(s.substring(0, s.length() - 2));
                } else {
                    txtUsersI.setText(intn.getString("NONE"));
                }
                ipw.setImage(project.getFolder("root").resolve(m.getFile()));
            }
        }
        if (ev.getWidget().equals(lstSounds)) {
            if (lstSounds.getSelectedIndex() > -1) {
                Media m = (Media) lstSounds.getSelectedValue();
                txtPathS.setText(m.getFile().toString());
                if (!m.getUsers().isEmpty()) {
                    String s = "";
                    for (String str : m.getUsers()) {
                        s += str + ", ";
                    }
                    txtUsersS.setText(s.substring(0, s.length() - 2));
                } else {
                    txtUsersS.setText(intn.getString("NONE"));
                }
                apwS.setAudio(project.getFolder("root").resolve(m.getFile()));
            }
        }
        if (ev.getWidget().equals(lstMusic)) {
            if (lstMusic.getSelectedIndex() > -1) {
                Media m = (Media) lstMusic.getSelectedValue();
                txtPathM.setText(m.getFile().toString());
                if (!m.getUsers().isEmpty()) {
                    String s = "";
                    for (String str : m.getUsers()) {
                        s += str + ", ";
                    }
                    txtUsersM.setText(s.substring(0, s.length() - 2));
                } else {
                    txtUsersM.setText(intn.getString("NONE"));
                }
                apwM.setAudio(project.getFolder("root").resolve(m.getFile()));
            }
        }
    }

    private void importMedia() {
        final Internationalization intn = Internationalization.getInstance();
        BFileChooser bf = new BFileChooser(BFileChooser.OPEN_FILE, intn.getString("MM.IMPORT"));
        bf.setFileFilter(new FileFilter() {

            @Override
            public boolean accept(File f) {
                if (f.isDirectory()) {
                    return true;
                }

                if (f.getName().endsWith(".png") || f.getName().endsWith(".wav") || f.getName().endsWith(".ogg")) {
                    return true;
                } else {
                    return false;
                }
            }

            @Override
            public String getDescription() {
                return intn.getString("MM.SUPPORTEDFILES");
            }
        });

        if (bf.showDialog(dialog)) {
            File file = bf.getSelectedFile();
            MediaImportDialog mid = new MediaImportDialog(dialog);
            if (mid.showDialog(Paths.get(file.toURI()))) {
                initLists();
                JOptionPane.showMessageDialog(dialog.getComponent(), intn.getString("MM.IMPORTOK"));
            }
        }
    }

    private void exportMedia() {
        Media m = null;

        final Internationalization intn = Internationalization.getInstance();
        BFileChooser bf = new BFileChooser(BFileChooser.SAVE_FILE, intn.getString("MM.EXPORT"));

        //Images
        FileFilter imgFilter = new FileFilter() {

            @Override
            public boolean accept(File f) {
                if (f.isDirectory()) {
                    return true;
                }

                if (f.getName().endsWith(".png")) {
                    return true;
                } else {
                    return false;
                }
            }

            @Override
            public String getDescription() {
                return intn.getString("MM.IMAGEFILES");
            }
        };

        //Sounds
        FileFilter sndFilter = new FileFilter() {

            @Override
            public boolean accept(File f) {
                if (f.isDirectory()) {
                    return true;
                }

                if (f.getName().endsWith(".wav")) {
                    return true;
                } else {
                    return false;
                }
            }

            @Override
            public String getDescription() {
                return intn.getString("MM.SOUNDFILES");
            }
        };

        //Music
        FileFilter mscFilter = new FileFilter() {

            @Override
            public boolean accept(File f) {
                if (f.isDirectory()) {
                    return true;
                }

                if (f.getName().endsWith(".ogg")) {
                    return true;
                } else {
                    return false;
                }
            }

            @Override
            public String getDescription() {
                return intn.getString("MM.MUSICFILES");
            }
        };

        String ending = "";
        switch (tabbed.getSelectedTab()) {
            case 0:
                bf.setFileFilter(imgFilter);
                if (lstImages.getSelectedIndex() > -1) {
                    m = (Media) lstImages.getSelectedValue();
                    ending = ".png";
                }
                break;
            case 1:
                bf.setFileFilter(sndFilter);
                if (lstSounds.getSelectedIndex() > -1) {
                    m = (Media) lstSounds.getSelectedValue();
                    ending = ".wav";
                }
                break;
            case 2:
                bf.setFileFilter(mscFilter);
                if (lstMusic.getSelectedIndex() > -1) {
                    m = (Media) lstMusic.getSelectedValue();
                    ending = ".ogg";
                }
                break;
            default:
                bf.setFileFilter(plugins.get(tabbed.getSelectedTab() - 3).getFileFilter());
                m = plugins.get(tabbed.getSelectedTab() - 3).getMedia();
                ending = ".dat";
                break;
        }

        if (m != null && bf.showDialog(dialog)) {
            Path file = bf.getSelectedFile().toPath();
            try {
                Files.copy(Project.getInstance().getFolder("root").resolve(m.getFile()), file.getParent().resolve(file.getFileName().toString() + ending));
            } catch (IOException ex) {
                log.error(ex);
            }
            JOptionPane.showMessageDialog(dialog.getComponent(), intn.getString("MM.EXPORTOK"));
        }
    }
}
